package com.itheima.mybatis.framework;

import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ：sean
 * @date ：Created in 2020/6/29
 * @description ：Executor类，用于实现SQL语句的执行，主要是调用JDBC来实现SQL语句的执行
 * @version: 1.0
 */
public class HmExecutor {
  private HmConfiguration configuration;

  public HmExecutor(HmConfiguration configuration) {
    this.configuration = configuration;
  }

  /**
   * 简单实现
   * @param mapperId 映射文件的namespace+id
   * @param <T>
   * @return
   * @throws Exception
   */
  public <T> List<T> executeQuery(String mapperId) throws Exception {
    List<T> list = new ArrayList<>();
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
      // 获取数据库连接 （可扩展为从连接池获取连接）
      Class.forName(configuration.getDriver());
      connection = DriverManager.getConnection(configuration.getUrl(),configuration.getUsername(),configuration.getPassword());

      // 获取到mapper信息对象
      HmMapper mapper = configuration.getMappers().get(mapperId);
      if(mapper == null){
        return null;
      }

      // 获取SQL (简单实现)
      String sql = mapper.getSql();

      preparedStatement = connection.prepareStatement(sql);
      resultSet = preparedStatement.executeQuery();
      String resultType = mapper.getResultType();
      // 使用反射机制,把数据封装到POJO对象中（把数据库每行封装成POJO对象，再封装成集合）
      Class clazz = Class.forName(resultType);
      Method[] mehtods = clazz.getMethods();
      List<String> columnNames = new ArrayList<>();
      ResultSetMetaData metaData = resultSet.getMetaData();
      int count = metaData.getColumnCount();
      for(int i = 1; i <= count; i++) {
        columnNames.add(metaData.getColumnLabel(i));
      }
      Object object = null;
      while (resultSet.next()) {
        object = clazz.newInstance();
        for(String columnName : columnNames) {
          for(Method method: mehtods) {
            if(method.getName().equalsIgnoreCase("set" + columnName)) {
              method.invoke(object,resultSet.getObject(columnName));
            }
          }
        }
        list.add((T) object);
      }
    } catch (Exception e) {
      throw e;
    } finally {
      if(resultSet != null) {
        resultSet.close();
      }
      if(preparedStatement != null) {
        preparedStatement.close();
      }
      if(connection != null){
        connection.close();
      }
    }
    return list;
  }
}
